package com.mindata.blockchain.common;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Random;

/**
 * User: jasperxgwang
 * Date: 2018-7-19 15:37
 */
@Slf4j
public class RetryUtils<T> {

    protected final Random random = new Random();


    /**
     * 重试操作
     *
     * @param exec    执行动作
     * @param retries 重试次数
     * @return null 执行失败
     * @throws IOException
     */
    public ResultPack<T> execRetries(ExecHttpApplication<T> exec, int retries) {
        int attempt = 0;
        ResultPack<T> result;
        int backoff = 1000;
        boolean tryAgain;
        do {
            ++attempt;
            //执行请求
            result = exec.request();
            tryAgain = result.isFailed() && attempt <= retries;
            backoff = getBackoffTime(backoff, tryAgain);
        } while (tryAgain);
        if (result.isFailed()) {
            log.warn("execRetries after [{}] attempts", attempt);
        }
        return result;
    }


    private int getBackoffTime(int backoff, boolean tryAgain) {
        if (tryAgain) {
            int sleepTime = backoff / 2 + this.random.nextInt(backoff);
            this.sleep((long) sleepTime);
            if (2 * backoff < 60000) {
                backoff *= 2;
            }
        }
        return backoff;
    }

    protected void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
